September 95 - Implementing Shared Internet Preferences With Internet Config
Implementing Shared Internet Preferences With
Quinn "the Eskimo !"
Having to enter the same Internet preferences, such as e-mail address and news
server, into multiple applications is bothersome not just for users, but also for
developers who must create the user interface associated with them. The Internet
Configuration System (IC) provides a simple user application for setting preferences,
and an API for getting the preferences from a database that's shared by all applications.
It's easy to add IC support to your application and take advantage of the flexibility
gained by IC's use of the Component Manager -- a valuable technique in itself.
Preferences, like nuclear weapons, proliferate. At times it seems that the major
developers are engaged in a "preferences race," where each one tries to gain the upper
hand by adding a dozen new preferences in each new release. Like the arms race, the
preferences race is obviously counterproductive, even dangerous, and yet no one
knows how to stop it.
Some of the worst offenders are Internet-related applications. How many times have
you had to enter your e-mail address into a configuration window? And what about
your preferred type and creator for JPEG files? Doesn't this just seem like a waste of
your time? The Internet Configuration System, or Internet Config for short, spares
everyone this trouble. And it spares developers the complexities of implementing these
preferences in each application.
This article takes you inside Internet Config. Take a good look at the design: IC
implements its shared library as a component, and uses switch glue to provide a
default implementation if the component is absent. Using the Component Manager to
implement shared libraries is a helpful technique not just for IC, but for other APIs as
well. Note too that Internet Config is useful for more than its name implies. For
example, the extension-to-file-type mapping database is useful for any program that
deals with "foreign" file systems. Indeed, IC is a perfectly valid mechanism for storing
private preferences that have nothing to do with the Internet.
Although IC is intended as an abstract API, all its source code is placed in the public
domain -- a condition of its development. This lets me illustrate the text with snippets
from the actual implementation and gives you full access to the source code. Both the IC
user's kit and the IC developer's kit, which contain code and documentation, are
included on this issue's CD. Note that Internet Config was developed independently and
is not supported by Apple.
The latest versions of the kits are always available from the ftp sites
ftp://ftp.share.com/pub/internet-configuration/ and
ftp://redback.cs.uwa.edu.au/Others/Quinn/Config/. In addition, the user kit is
available from UMich and Info-Mac mirrors around the world.*
As with any new piece of software intended to be widely adopted, Internet Config needs
developer support in order to be successful. I hope this article raises the awareness of
IC in the developer community and prompts some of you to support it.
INTERNET CONFIG FROM THE OUTSIDE
Before going inside Internet Config, it's important to know how the system works as a
whole. The best way to do this is to get a copy of the Internet Config application and run
it (there's a copy on this issue's CD), but if you're too relaxed to do that right now,
keep reading for a description of the basics. We'll look at IC first from the user's
perspective and then from the programmer's point of view.
THE USER'S PERSPECTIVE
To the user, Internet Config is a proper Macintosh application. It supports the standard
menu commands New, Open, Save, Save As, and so on. The only difference is that the
files it operates on are preferences files. Figure 1 shows Internet Config and its
related files.
Figure 1. Internet Config and its related files -- what the user sees
The first time the Internet Config application is run, it installs the Internet Config
Extension into the Extensions folder and creates a new, blank Internet Preferences file
in the Preferences folder. It then displays the main window, shown in Figure 2, which
allows the user to edit the preferences.
Figure 2. The Internet Config application's main window
Each of the buttons in the main window displays another window containing a group of
related preferences. For example, the Personal button brings up the window shown in
Figure 3. The user enters preferences into each of these windows and then quits and
saves the preferences.
Figure 3. The Personal preferences window
From this point on, the user never has to enter those preferences again. Any IC-aware
program the user runs simply accesses the preferred settings without requiring them
to be reentered. This makes the user very happy (we presume).
Users can even run IC-aware applications "out of the box" -- they don't have to run
Internet Config first. If the Internet Config Extension isn't installed, IC-aware client
applications access the Internet Preferences file directly instead of through the
extension (as shown by the black arrows in Figure 1). The way this is done is
described later in the section "The Inner Workings of an API Routine.
THE PROGRAMMER'S PERSPECTIVE
To programmers, Internet Config consists of a set of interface files that define the API,
and a library to be statically linked to their programs. IC can be used from all of the
common Macintosh development environments: MPW, THINK, and Metrowerks; Pascal
and C; and 680x0 and PowerPC. The examples in this article, like IC itself, were
written in THINK Pascal.
What's in an IC preference. Before getting to the details of the API, you need to
know more about IC preferences. In IC, a preference is an item of information that's
useful to the client application program. Each preference has three components: its
key, its data, and its attributes.
• The key is a Str255 that identifies the preference. You can use the key to
fetch the data and attributes.
• The data is an untyped sequence of bytes that represents the value of the
preference. The data's structure is determined by the client program. The
structures of the common preferences are defined in the IC programming
documentation.
• The attributes represent information about the preference that's
supplementary to the preference data, such as whether the preference is
read/write or read-only.
In the e-mail address preference, for example, the key is the string "Email". If you
pass this string into IC, it returns the preference's data and attributes. By convention,
the data for the key "Email" is interpreted as a Pascal string containing the user's
preferred e-mail address.
IC's core API routines. Internet Config has the following core API routines.
Although the API has a lot more depth, these four routines are all you need to program
with IC.
FUNCTION ICStart (VAR inst: ICInstance; creator: OSType): ICError;
FUNCTION ICStop (inst: ICInstance): ICError;
FUNCTION ICFindConfigFile (inst: ICInstance; count: Integer;
folders: ICDirSpecArrayPtr): ICError;
FUNCTION ICGetPref (inst: ICInstance; key: Str255; VAR attr: ICAttr;
buf: Ptr; VAR size: LongInt): ICError;
The ICStart routine is always called first. Here you pass in your application's creator
code so that future versions of IC can support application-dependent preferences.
ICStart returns a value of type ICInstance; this is an opaque type that must be passed to
every other API call. ICStop is called at the termination of your application to dispose
of the ICInstance you obtained with ICStart.
ICFindConfigFile is called immediately after ICStart. IC uses this routine to support
applications with double-clickable user configuration files, a common phenomenon
among Internet applications. If you need to support these files, see the IC programming
documentation; otherwise, just pass in 0 for the count parameter and nil for the
folders parameter.
The ICGetPref routine takes a preference key and returns the preference's attributes
in attr and its data in the buffer pointed to by buf. The maximum size of the buffer is
passed in as size, which is adjusted to the actual number of bytes of preference data.
The simplest example. The program in Listing 1 demonstrates the simplest
possible use of IC technology. All it does is write the user's e-mail address to the
standard output. This program calls the four core API routines: it begins by calling
ICStart and terminates with an ICStop call; it calls ICFindConfigFile with the default
parameters and uses ICGetPref to fetch the value of a specific preference -- in this
case the user's e-mail address.
Listing 1. The simplest IC-aware program
PROGRAM ICEmailAddress;
{ The simplest IC-aware program. It simply outputs the user's }
{ preferred e-mail address. }
USES
ICTypes, ICAPI, ICKeys; { standard IC interfaces }
VAR
instance: ICInstance; { opaque reference to IC session }
str: Str255; { buffer to read e-mail address into }
str_size: LongInt; { size of above buffer }
junk: ICError; { place to throw away error results }
junk_attr: ICAttr; { place to throw away attributes }
BEGIN
{ Start IC. }
IF ICStart(instance, '????') = noErr THEN BEGIN
{ Specify a database, in this case the default one. }
IF ICFindConfigFile(instance, 0, NIL) = noErr THEN BEGIN
{ Read the real name preferences. }
str_size := sizeof(str);{ 256 bytes -- a similar construct }
{ wouldn't work in C }
IF ICGetPref(instance, kICEmail, junk_attr, @str, str_size)
= noErr THEN BEGIN
writeln(str);
END; { IF }
END; { IF }
{ Shut down IC. }
junk := ICStop(instance);
END; { IF }
END. { ICEmailAddress }
INSIDE INTERNET CONFIG
The IC API just described is really all you need to know to make your program
IC-aware; now we'll get into the guts of Internet Config to see how it achieves its
magic. We'll look first at its underlying design and then at how its internal structures
work together.
THE IC DESIGN: A SIMPLE, EXPANDABLE SYSTEM
The design requirements for Internet Config evolved during early discussions of what
an Internet configuration system might look like (see "How Internet Config Came to
Be"). These requirements guided the development process and form the basic structure
of Internet Config -- an efficient, expandable system that's easy to use and easy to
support.
______________________________
HOW INTERNET CONFIG CAME TO BE
Designing Internet Config was a complicated business. The process began in
March 1994 with a discussion on the Usenet newsgroup comp.sys.mac.comm.
Many people thought simplifying Internet configuration was a good idea, but
few agreed how best to achieve the goal, or indeed what the goal was.
We set up a mailing list to swap ideas, and discussion continued apace for
weeks. One of the biggest issues was the disparity between the problems we
wanted to solve and the ones we could solve given our limited resources.
After a week or two of thrashing out the requirements, Peter N. Lewis, Marcus
Jager, and I proposed the first API. A few weeks later we shipped the first
implementation of the Internet Config Extension.
The problem IC solves is actually quite simple, so it didn't take long to
implement the design. As usual, however, it took some time to go from a
working implementation to a final product -- we shipped Internet Config 1.0
in December 1994. Though we've made minor additions and changes, the
initial design survives to this day.
______________________________
Internet Config can accept sweeping changes while maintaining API compatibility, and
it allows for patches to support future extensions and bug fixes. We couldn't achieve
such expandability with a simple shared preferences implementation, and the
consequent loss of simplicity caused a lot of debate during the development process.
The need for simplicity was implicit from the beginning. To add support for Internet
Config, application developers have to revise their code. Developers tend to be lazy --
hey, I mean that as a compliment -- and generally prefer simple systems to
complicated ones. Developer support is critical for success, so we kept the system
simple. Still, it isn't so simple as to compromise the need for expandability.
As we've already seen, IC has several other interesting design features. The API
supports applications with double-clickable user configuration files. The Internet
Config user application accesses all the Internet preferences through the API, and is
thereby isolated from the implementation details. IC-aware applications work even if